﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace ArgusLib.InteropServices
{
	public interface INativeWrapper : IDisposable
	{
		object Structure { get; }
		IntPtr Pointer { get; }
		Type StructureType { get; }
		bool IsDisposed { get; }

		event EventHandler Disposed;

		void Initialize(object structure, IntPtr pointer);
	}

	public abstract class NativeWrapper<T> : INativeWrapper
	{
		protected T Structure { get; private set; }
		protected IntPtr Pointer { get; private set; }
		object INativeWrapper.Structure { get { return this.Structure; } }
		IntPtr INativeWrapper.Pointer { get { return this.Pointer; } }
		Type INativeWrapper.StructureType { get { return typeof(T); } }
		public bool IsDisposed { get { return this.Pointer == IntPtr.Zero; } }

		public event EventHandler Disposed;

		public NativeWrapper()
		{ }

		~NativeWrapper()
		{
			this.Dispose();
		}

		void INativeWrapper.Initialize(object structure, IntPtr ptr)
		{
			if (this.Pointer != IntPtr.Zero)
				throw new Exception("The object has already been initialized.");

			if (!(structure is T))
				throw new ArgumentException("structure");

			this.Structure = (T)structure;
			this.Pointer = ptr;
		}

		protected abstract void DisposeCore();

		public void Dispose()
		{
			if (this.IsDisposed == true)
				return;
#if Log
			Log.WriteLine(this.ToString() + " disposing...");
#endif
			this.DisposeCore();
			this.Pointer = IntPtr.Zero;
			this.Structure = default(T);
#if Log
			Log.WriteLine(this.ToString() + " disposed");
#endif
			if (this.Disposed != null)
				this.Disposed(this, EventArgs.Empty);
		}
	}
}
